import logging
import locale
import os
import re
import cgi
import datetime
import urllib
import wsgiref.handlers

from django.utils import simplejson 
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.db import djangoforms

from food import datamodel

class MainPage(webapp.RequestHandler):
  def get(self):
    user = users.get_current_user()
    user_accesslevel = "normal"
    user_loggedin = ""
    path = os.path.join(os.path.dirname(__file__), 'templates/loggedout.html')
	
    if user:
      url = users.create_logout_url(self.request.uri)
      url_linktext = ''

      user_loggedin = "<a id='usernick' href='#'>"+user.nickname() + "</a>" 
      path = os.path.join(os.path.dirname(__file__), 'templates/loggedin.html')
				
    else:
      url = users.create_login_url(self.request.uri)
      url_linktext = 'Login'

    template_values = {
      'url': url,
      'url_linktext': url_linktext,
      'user_loggedin': user_loggedin,
      'user_accesslevel': user_accesslevel,
    }

    self.response.out.write(template.render(path, template_values))



class RPCHandler(webapp.RequestHandler):
  """ Allows the functions defined in the RPCMethods class to be RPCed."""
  def __init__(self):
    webapp.RequestHandler.__init__(self)
    self.methods = RPCMethods()

  def get(self):
    func = None
    action = self.request.get('action')
    if action:
      if action[0] == '_':
        self.error(403) # access denied
        return
      else:
        func = getattr(self.methods, action, None)
        logging.debug('func: %s' % func)
        if not func:
          self.error(404) # file not found
          return
        result = func(self.request)
        self.response.out.write(simplejson.dumps(result))
    else:
      self.error(403)
      
class RPCMethods:
  """ Defines the methods that can be RPCed.     NOTE: Do not allow remote callers access to private/protected "_*" methods.     """
 
  def GetProfile(self, request):
    user = users.get_current_user()
    if user:
      profile = db.GqlQuery("SELECT * "
                            "FROM Profile "
                            "WHERE user = :1 ",
                            user).get()

      if profile:
        logging.debug("Profile found for %s" % user.nickname() )
        return {'name': profile.name,
                'height' : profile.height,
                'birthyear' : profile.birthyear,
                'activitylevel' : profile.activitylevel,
                'lossprofile' : profile.lossprofile,
                'gender' : profile.gender,
                'calculateneed' : profile.calculateneed,
                'caloricneed' : profile.caloricneed }
      else:
        logging.debug("NO Profile found for %s" % user.nickname() )
        return {'error': 'no profile found'}
    else:
      return {'error': 'no user'}

  def StoreProfile(self, request):
    user = users.get_current_user()
    if user:
      logging.debug('storing user: %s' % user.nickname())


      profile = db.GqlQuery("SELECT * "
                            "FROM Profile "
                            "WHERE user = :1 ",
                            user).get()

      if not profile:
        # update the current profile with the passed data.
        profile = datamodel.Profile(user=user)
      
      errors = {}
      name = cgi.escape(request.get("name"))
      birthyear = cgi.escape(request.get("birthyear"))
      height = cgi.escape(request.get("height"))
      calculateneed = cgi.escape(request.get("calculateneed"))
      caloricneed = cgi.escape(request.get("caloricneed"))
      gender = cgi.escape(request.get("gender"))
      lossprofile = cgi.escape(request.get("lossprofile"))
      activitylevel = cgi.escape(request.get("activitylevel"))

      if not re.match("[a-zA-Z0-9 ]+$",name):
        errors["name"] = "name contains bogus letters"
      if not re.match("[0-9]{3}$",request.get("height")):
        errors["height"] = "height must be all digits and between 100-999"
      if not re.match("[0-9]{4}$",request.get("birthyear")):
        errors["birthyear"] = "birthyear must be all digits and between 1000-9999"
      if calculateneed != "true" and not re.match("[0-9]{3,4}$",caloricneed):
        errors["caloricneed"] = "caloricneed must be all digits and between 100-9999"
        
      if len(errors) != 0:
        return {'error': 'validation error','errors' : errors }
      else:
        # we can store the profile, and return OK
        profile.name = name
        profile.birthyear = int(birthyear)
        profile.height = int(height)
        profile.calculateneed = bool(calculateneed)
        profile.lossprofile = lossprofile
        profile.activitylevel = activitylevel
        profile.gender = gender
        if calculateneed == "true":
          profile.caloricneed = calculateCaloricNeed(profile)
        else:
          profile.caloricneed = caloricneed
        profile.put()
        return {'result': 'OK'}
    else:
      return {'error': 'no user'}

def calculateCaloricNeed(profile):
  age = datetime.date.today() - datetime.date(profile.birthyear,6,1)
  age = age.days / 365
  weight = getMetric( profile.user, "weight" )

  bmr = 0
  if profile.gender=="male":
    bmr = 66.5 + (13.75 * weight) + (5.003 * profile.height) - (6.775 * age); """ Men """
  else:
    bmr = 655.1 + (9.563 * weight) + (1.850 * profile.height) - (4.676 * age); """ Women """

  act_multiplier = 1.2
	
  if profile.activitylevel=="light":
    act_multiplier = 1.3
  elif profile.activitylevel=="moderate":
    act_multiplier = 1.4
  elif profile.activitylevel=="rigorous":
    act_multiplier = 1.5

  result = act_multiplier*bmr;
	
  if profile.lossprofile=="0.5kg pr week":
    result = result - 500
  elif  profile.lossprofile=="1kg pr week":
    result = result - 1000
  elif  profile.lossprofile=="1kg pr month":
    result = result - 250

  return int(result)

""" Fetches a metric from the Metric database,
    so far just a stub until metric storing is implemented """
def getMetric(user, metric):
	return 90
	
application = webapp.WSGIApplication([
  ('/', MainPage),
  ('/jsonrpc', RPCHandler),
], debug=True)


def main():
  run_wsgi_app(application)


if __name__ == '__main__':
  main()
